package com.peycard.service;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.peycard.util.Constantes;
import com.peycard.util.Utils;

/**
 * @author Aline Ordoñez
 * 
 */
@Service
public class BaseService extends BaseTransaction {

	/**
	 * Constructor sin argumentos
	 * 
	 * @throws IOException
	 */
	public BaseService() throws IOException {
		super();
	}

	private static final Logger LOGGER = LoggerFactory
			.getLogger(BaseService.class);

	/**
	 * String que representa la descripción obtenida cuando la operación fue
	 * exitosa.
	 */
	private String message;
	/**
	 * String necesario para realizar peticiones, debe coincidir con el que está
	 * registrado el servidor. Cambia en cada operación exitosa.
	 */
	private String token;

	/**
	 * Lista de Strings que se obtiene en la respuesta.
	 */
	private List<String> list;

	/**
	 * Método que genera el mensaje para obtener la lista de todos registros,
	 * dependiendo del proccessingCode es el tipo de lista que solicita.
	 * 
	 * @param proccessingCode
	 * @param metadata
	 * @param dataStructure
	 * @param listKey
	 * @throws IOException
	 * @throws ParseException
	 */
	public void listISOMessage(String proccessingCode, String metadata,
			String dataStructure, String listKey) throws IOException,
			ParseException {
		BaseTransaction base = initBaseValues();
		LOGGER.info("proccessingCode: " + proccessingCode);
		base.setField3_n6_idop(proccessingCode);
		LOGGER.info("metadata: " + metadata);
		base.setField126_lllvar_metadata(metadata);
		LOGGER.info("dataStructure: " + dataStructure);
		base.setField127_lllvar_data(dataStructure);

		base.sendMessage();

		if (baseResponse(base)) {
			list = new ArrayList<String>();
			Map<String, String> map = Utils.baseMap(base);
			String string = map.get(listKey);
			if (string != null) {
				list = Utils.getListValues(string);
			} else {
				message = Utils.getMessage(base);
			}
		} else {
			message = "Ocurrió un problema, inténtelo nuevamente.";
		}
	}

	/**
	 * @param data
	 * @throws IOException
	 * @throws ParseException
	 */
	public void transactionListISOMessage(String data) throws IOException,
			ParseException {

		BaseTransaction base = initBaseValues();
		base.setField3_n6_idop(Constantes.ISO003_TRANSACTION_REPORT);
		base.setField126_lllvar_metadata(Constantes.TRANSACTION_METADATA);
		base.setField127_lllvar_data(data);

		base.sendMessage();

		if (baseResponse(base)) {
			list = new ArrayList<String>();
			Map<String, String> map = Utils.baseMap(base);
			String transaction = map.get(Constantes.TRANSACTIONS_LIST_KEY);
			if (transaction != null) {
				list = Utils.getListValues(transaction);
			} else {
				message = Utils.getMessage(base);
			}
		} else {
			message = "Ocurrió un problema, inténtelo nuevamente.";
		}
	}

	/**
	 * Método que llena los campos para generar el mensaje ISO en el proceso de
	 * agregar y editar un registro.
	 * 
	 * @param proccessingCode
	 * @param metadata
	 * @param dataStructure
	 * @return boolean
	 * @throws IOException
	 * @throws ParseException
	 */
	public boolean isoMessageRequest(String proccessingCode, String metadata,
			String dataStructure) throws IOException, ParseException {
		boolean request = true;
		BaseTransaction base = initBaseValues();
		base.setField3_n6_idop(proccessingCode);
		base.setField126_lllvar_metadata(metadata);
		base.setField127_lllvar_data(dataStructure);

		base.sendMessage();

		if (!baseResponse(base)) {
			message = Utils.getMessage(base);
			request = false;
		}
		return request;
	}

	public byte[] signRequest(String idTx) throws IOException, ParseException {
		byte[] sign = null;
		BaseTransaction baseSign = initBaseValues();
		baseSign.setField3_n6_idop(Constantes.ISO003_TRANSACTION_SIGN);
		baseSign.setField126_lllvar_metadata(Constantes.SIGN_METADATA);
		baseSign.setField127_lllvar_data(idTx);
		baseSign.sendMessage();

		boolean response = baseResponse(baseSign);
		if (response) {
			Map<String, String> map = Utils.baseMap(baseSign);
			if (map.containsKey(Constantes.SIGN_KEY)
					&& map.get(Constantes.SIGN_KEY) != null) {
				sign = map.get(Constantes.SIGN_KEY).getBytes();
			}
		} else {
			message = Utils.getMessage(baseSign);
		}
		return sign;
	}

	/**
	 * * Método que valida si la respuesta obtenida desde el servidor concuerda
	 * con la petición enviada.
	 * 
	 * @param base
	 * @return
	 * @throws IOException
	 */
	private boolean baseResponse(BaseTransaction base) throws IOException {
		boolean response = false;
		token = base.getField125_resp_lllvar_token();
		String field39 = base.getField_39_resp_n2_cod_resp().toString();

		if (field39.equals(Constantes.ISO039_VALUE)) {
			String field41send = base.getField41_an16_idterminal();
			String field41resp = base.getField41_resp_an16_idterminal();
			if (field41send.equals(field41resp)) {
				response = true;
			}
		}
		return response;
	}

	private BaseTransaction initBaseValues() throws IOException, ParseException {
		BaseTransaction base = new BaseService();
		base.setField100_llvar_id_op_x(Constantes.ISO100_PORTAL);
		base.setField124_n1_token_present(Constantes.ISO0124_FIELD125_IS_PRESENT);
		base.setField125_lllvar_token(token);
		return base;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * @param message
	 *            the message to set
	 */
	public void setMessage(String message) {
		this.message = message;
	}

	/**
	 * @return the list
	 */
	public List<String> getList() {
		return list;
	}

	/**
	 * @param list
	 *            the list to set
	 */
	public void setList(List<String> list) {
		this.list = list;
	}

	/**
	 * @return the token
	 */
	public String getToken() {
		return token;
	}

	/**
	 * @param token
	 *            the token to set
	 */
	public void setToken(String token) {
		this.token = token;
	}
}
